/******************************************************************
 * Created by: GOh CHee Hong                                      
 * Date of Creation: 1/Jan/2009            
 
 *                                                                
 * Description: This class is in charge of downloading the feeds
 ******************************************************************/
/*
 * FeedExpress
 * (C) Copyright 2003 Jeppe Cramon (jeppe@cramon.dk)
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Disclaimer:
 * -----------
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied. The entire risk as to the
 * quality and performance of the software is with you. Should the
 * software prove defective, you assume the cost of all necessary
 * servicing, repair, or correction. In no event shall the author,
 * copyright holder, or any other party who may redistribute the
 * software be liable to you for damages, including any general,
 * special, incidental, or consequential damages arising out of
 * the use or inability to use the software (including, but not
 * limited to, loss of data, data being rendered inaccurate, loss of
 * business profits, loss of business information, business
 * interruptions, loss sustained by you or third parties, or a
 * failure of the software to operate with any other software) even
 * if the author, copyright holder, or other party has been advised
 * of the possibility of such damages. 
 * 
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Xml;
using System.Collections;
using Pbdms.BusinessLogic;
using Pbdms.Common.Interfaces;
using Pbdms.Common.DataObject;
using Pbdms.NetworkDealer;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Pbdms.BusinessLogic.RSS
{
    public class FeedManager
    {
        //refresh handlers
        public event EventHandler RefreshStart;
        public event EventHandler RefreshDone;
        public event EventHandler NewFeeds;
        public event EventHandler RefreshFailed;
        public SubscriptionManager.RefreshProcessHandler RefreshProcess;
        private Subscription subscription;
        private bool mIsRefreshing = false;

        private Common.Interfaces.ICache mCache;
        private IDictionary mNewFeedsSinceLastRefresh = Hashtable.Synchronized(new Hashtable());
        private bool hasInitializedSubscriptionReferences = false;
        public BusinessLogic.Network.NetworkController networkCtrller;

        public FeedManager(Subscription subscription)
        {
            this.subscription = subscription;
            this.mCache = CacheFactory.getInstance().getCacheHandler();
       
        }

        public IDictionary feeds
        {
            get
            {
                IDictionary returnValue = (IDictionary)mCache.getAll(subscription);
                if (!hasInitializedSubscriptionReferences && returnValue != null)
                {
                    foreach (FeedEntry feed in returnValue.Values)
                    {
                        feed.subscription = subscription;
                    }
                    hasInitializedSubscriptionReferences = true;
                }
                return returnValue; ;
            }
        }
        /// <summary>
        /// Returns the number of unread feeds
        /// </summary>
        /// <returns></returns>
        public int getUnreadCount()
        {
            IDictionary feeds = (IDictionary)mCache.getAll(subscription);
            int count = 0;
            if (feeds == null)
            {
                return count;
            }

            foreach (FeedEntry feed in feeds.Values)
            {
                if (!feed.isRead)
                {
                    count++;
                }
            }
            return count;
        }

        /// <summary>
        /// Saves the entire Feed cache to disk. Seperate saving of feeds isn't supported.
        /// </summary>
        public void saveCompleteFeedCache()
        {
            mCache.saveCache();
        }

        /// <summary>
        /// Clears the feed cache
        /// </summary>
        public void clearCache()
        {
            mCache.remove(subscription);
        }

        /// <summary>
        /// Marks all feeds as read
        /// </summary>
        public void markAllAsRead()
        {
            IDictionary feeds = (IDictionary)mCache.getAll(subscription);
            foreach (FeedEntry feed in feeds.Values)
            {
                feed.isRead = true;
            }
        }

        /// <summary>
        /// Marks all feeds as unread
        /// </summary>
        public void markAllAsUnRead()
        {
            IDictionary feeds = (IDictionary)mCache.getAll(subscription);
            foreach (FeedEntry feed in feeds.Values)
            {
                feed.isRead = false;
            }
        }

        /// <summary>
        /// Refreshes the feeds, by contacting the feed server
        /// </summary>
        public void refreshFeeds()
        {
            Common.DataObject.Buddy buddy = networkCtrller.friendsControl.getAFriendByKeyID(subscription.info.FriendID);
            if (buddy == null)
            {
                return;
                
            }
            else
            {
                if (buddy.IpAdd == null)
                {
                    return;
                }
            }
            lock (this)
            {
                if (mIsRefreshing)
                {
                    return;
                }
                else
                {
                   
                    mIsRefreshing = true;
                }
            }
            AuthTcpClient authTcpClient= new AuthTcpClient(buddy.IpAdd,NetworkDealer.NetworkDealer.LISTEN_PORT,buddy.KeyID,networkCtrller.keyControl,networkCtrller.publicKeyControl,networkCtrller.friendsControl);
            authTcpClient.Connect();
            //if not authenticated return;
            if (authTcpClient.IsAuthenticated() == false)
            {
                lock (this)
                {
                    mIsRefreshing = false;
                    
                }
                return;
            }
            MemoryStream memory = new MemoryStream();
            try
            {
            NetworkMessage message = new NetworkMessage();
            message.TypeOfMessage = NetworkDealer.NetworkDealer.FEED_REQUEST;
            
            
                authTcpClient.sendMessage(message);
                message = authTcpClient.receiveMessage();
              
                if (message.TypeOfMessage == NetworkDealer.NetworkDealer.FEED_RESPONSE)
                {
                    long totalSize = long.Parse(message.MessageContent);
                    long rby = 0;
                    int perc = 0;
                   
                    while (rby < totalSize)
                    {
                        byte[] buffer = null;
                        //Read from the Network Stream
                        try
                        {
                            int length = 1024;
                            if (rby + 1024 > totalSize)
                            {
                                length = (int)(totalSize - rby);
                            }


                            buffer = authTcpClient.receiveBytes();

                            memory.Write(buffer, 0, buffer.Length);
                            rby = rby + length;
                            perc = (int)(((double)rby / (double)totalSize) * 100.00);
                         
                        }
                        catch
                        {
                            break;
                        }
                    }
                    if (rby == totalSize)
                    {
                        memory.Seek(0, SeekOrigin.Begin);
                        
                        BinaryFormatter formatter = new BinaryFormatter();
                        Rss.RssChannel rssChannel=(Rss.RssChannel)formatter.Deserialize(memory);
                        Rss.RssFeed feed = new Rss.RssFeed();
                        feed.Channels.Add(rssChannel);
                        string saveToTemp=Common.Global.getTempFolder() + "\\" + subscription.Key;
                        feed.Write(saveToTemp);
                         
                        XmlDocument xdoc= new XmlDocument();
                        xdoc.Load(saveToTemp);
                        Rss20Reader rssReader= new Rss20Reader();
                        IDictionary feeds=rssReader.readFeeds(xdoc);
                        bool sendNewFeedsEvent = false;
                        // Set feed reference to subscription
                        foreach (FeedEntry aFeed in feeds.Values)
                        {
                            aFeed.subscription = subscription;
                        }
                        if (mCache.updateAll(subscription, feeds))
                        {
                            sendNewFeedsEvent = true;
                        }
                        // Signal new feeds?
                        if (sendNewFeedsEvent)
                        {
                            if (NewFeeds != null)
                            {
                                NewFeeds(this.subscription, EventArgs.Empty);
                            }
                        }
                    }
                    else
                    {

                    }

                }
                else
                {
                    throw new Exception("error");
                }
            }
            catch
            {
              
            }
            finally
            {
                authTcpClient.Close();
                if (memory != null)
                {
                    memory.Close();
                }
                lock (this)
                {
                    mIsRefreshing = false;

                }
            }
        }
  

    }
}
